/**
 * 🛑 此文件用于存放那些在APP高频使用的 Query，以及基于接口数据的派生数据
 *
 * 注意：
 * 0. 不要滥用❗不要滥用❗不要滥用❗
 * 1. queryKey 必须绑定接口名字和接口的参数
 * 2. 不能依赖除接口数据外的其他数据
 * 3. 接口必须是高频使用（3次以上，且传参相同）
 */

import { createSharedComposable } from '@peng_kai/kit/libs/vueuse';
import { useAuthed } from '~/composables/useAuthed';
import { usePeriodicPopup } from '~/composables/usePeriodicPopup';
import { useAppSocket } from '~/modules/socket/useAppSocket';
import { jsBridge } from '~/utils/defines';

/** 币种/余额信息 */
export const useCurrencyQuery = createSharedComposable(() => {
  const authed = useAuthed();
  const appSocket = useAppSocket();

  const currencyQry = useQuery({
    queryKey: [apis.apiCurrencyIndex.id],
    queryFn: () => apis.apiCurrencyIndex(undefined),
  });
  const cryptoList = computed(() => currencyQry.data.value?.crypto ?? undefined);
  const cryptoMap = computed(() => Object.fromEntries(cryptoList.value?.map(item => [item.currency, item]) ?? []));
  const fiatList = computed(() => currencyQry.data.value?.fiat ?? undefined);
  const fiatMap = computed(() => Object.fromEntries(fiatList.value?.map(item => [item.currency, item]) ?? []));
  const currencyList = computed(() => [...cryptoList.value ?? [], ...fiatList.value ?? []]);
  const currencyMap = computed(() => ({ ...cryptoMap.value, ...fiatMap.value }));

  const balanceQry = useQuery({
    enabled: authed,
    queryKey: [apis.apiUserBalance.id],
    queryFn: () => apis.apiUserBalance(undefined),
  });
  const balanceList = computed(() => balanceQry.data.value?.map(item => ({
    ...item,
    ...cryptoMap.value[item.currency],
    ...fiatMap.value[item.currency],
  })) ?? undefined);
  const balanceMap = computed(() => Object.fromEntries(balanceList.value?.map(item => [item.currency, item]) ?? []));

  appSocket.receive('CURRENCY_RATE_RESP', 'CurrencyRateResp', (res) => {
    queryClient.setQueryData([apis.apiCurrencyIndex.id], (oldData: any) => {
      if (!oldData)
        return;

      const newRate: Api.GetData<typeof apis.apiCurrencyIndex> = JSON.parse(JSON.stringify(oldData ?? {}));
      const newRateArr = Object.values(newRate ?? {}).flat();

      Object.entries(res.Data.Rates).forEach(([name, rates]) => {
        const target = newRateArr.find(x => x?.currency === name);
        if (target) {
          rates.USD && (target.usd_price = rates.USD);
          rates.USDT && (target.usdt_price = rates.USDT);
        }
      });

      return newRate;
    });
  });

  appSocket.receive('USER_ADD_BALANCE_RESP', 'AddBalanceResp', async (res) => {
    // TODO: 待优化，让活动变动的socket主动推送
    queryClient.invalidateQueries({
      queryKey: [apis.apiActivityCheckAvailableBonuses.id],
      exact: false,
    });

    /**
     * 暂时不处理由于游戏结果导致的余额变动，因为目前USER_ADD_BALANCE_RESP是没有等待动画结束的
     */
    // 7=bet，8=reward，排除掉游戏下单和派奖
    if (res.Data?.Type === 7 || res.Data?.Type === 8) {
      return;
    }

    if (res.Data?.Type === 6) {
      jsBridge.post('recharge', { currency: res.Data.Currency, amount: res.Data.Amount });
    }

    // updateBalance(res.Data.Currency, res.Data.Balance);
    appSocket.send('USER_BALANCE_REQ', 'BalanceResp', (data) => {
      data.Currency = res.Data.Currency;
      return data;
    });
  });
  appSocket.receive('USER_BALANCE_RESP', 'BalanceResp', (res) => {
    updateBalance(res.Data.Currency, res.Data.Amount, res.Data.BonusBalance);
  });

  /**
   * 更新余额
   * @param currency 币种
   * @param totalBalance 余额
   */
  function updateBalance(currency: string, totalBalance: string, bonusBalance: string = '0') {
    queryClient.setQueryData([apis.apiUserBalance.id], (oldData: any) => {
      if (!oldData)
        return;

      const newBalenceList: Api.GetData<typeof apis.apiUserBalance> = JSON.parse(JSON.stringify(oldData ?? {}));
      const target = newBalenceList.find(x => x.currency === currency);

      if (target) {
        target.balance = totalBalance || '0';
        target.bonus_balance = bonusBalance || '0';
      }

      return newBalenceList;
    });
  }

  return { currencyQry, balanceQry, cryptoList, cryptoMap, fiatList, fiatMap, currencyList, currencyMap, balanceList, balanceMap };
});

/** 邀请渠道相关的信息 */
export const useInviteChannelQuery = createSharedComposable(() => {
  const authed = useAuthed();

  const inviteChannelQry = useQuery({
    enabled: authed,
    queryKey: [apis.apiInviteChannel.id],
    queryFn: () => apis.apiInviteChannel({}),
  });
  const channelList = computed(() => inviteChannelQry.data.value?.list);
  const channelListForAntdSelectOptions = computed(() => [
    { value: '', label: $t('tTzcsuuLs3OmtBkOds9Fn') },
    ...channelList.value?.map(x => ({ value: x.channel_id, label: x.name })) ?? [],
  ]);
  const defaultChannel = computed(() => inviteChannelQry.data.value?.list?.find(item => item.is_default));

  return { inviteChannelQry, channelList, channelListForAntdSelectOptions, defaultChannel };
});

/** 邀请统计 */
export const useInviteStatisticsQuery = createSharedComposable(() => {
  const authed = useAuthed();

  const inviteStatsQry = useQuery({
    enabled: authed,
    queryKey: [apis.apiInviteStatistics.id],
    queryFn: () => apis.apiInviteStatistics({
      start_time: dayjs().utc().startOf('month').valueOf(),
      end_time: dayjs().utc().endOf('month').valueOf(),
    }),
  });
  const inviteStats = computed(() => inviteStatsQry.data.value);

  return { inviteStatsQry, inviteStats };
});

/** 游戏列表/分类信息 */
export const useGameAllQuery = createSharedComposable(() => {
  const gameAllQry = useQuery({
    queryKey: [apis.apiGameAll.id],
    queryFn: () => apis.apiGameAll(undefined),
  });
  const gameTypes = computed(() => gameAllQry.data.value?.game_list ?? []);
  const gameList = computed(() => Object.values(gameAllQry.data.value?.game_map ?? {}));
  const gameMap = computed(() => gameAllQry.data.value?.game_map);

  return { gameAllQry, gameTypes, gameList, gameMap };
});

/** 奖励相关的信息 */
export const useBonusesQuery = createSharedComposable(() => {
  const authed = useAuthed();
  const bonusesQry = useQuery({
    enabled: authed,
    queryKey: [apis.apiActivityCheckAvailableBonuses.id, 'in-queries'],
    queryFn: () => apis.apiActivityCheckAvailableBonuses(undefined),
    refetchOnWindowFocus: true,
  });
  const bonuses = computed(() => bonusesQry.data.value);

  /** 可领取奖励的剩余时间。不可领取时是时间戳；可领取时是0 */
  const bonusesAvailableAt = computed(() => {
    const data: any = bonusesQry.data.value;
    const dataUpdateAt = bonusesQry.dataUpdatedAt.value;
    const availableAt: Record<string, any> = {};

    Object.keys(data ?? {}).forEach((key) => {
      const expire = data[key]?.expire_second;

      if (typeof expire === 'number') {
        // 稍微加一点时间
        availableAt[key] = expire && dataUpdateAt + 1000 + expire * 1000;
      }
    });

    return availableAt as Record<keyof NonNullable<typeof bonuses.value>, number | undefined>;
  });

  /** 可领取的奖励数量 */
  const bonuseAvailableCount = computed(() => {
    let available = Object.values(bonuses.value ?? {}).filter(item => item.available).length;
    // 加上等级可领取数量
    if (bonuses?.value?.upgrade.available) {
      available = available - 1;
    }
    return available + Number(bonuses?.value?.upgrade.amount ?? 0);
  });

  // 奖励的定时器，用于自动刷新可领取奖励的剩余时间
  const timerIds: Record<string, number> = {};
  // 监听可领取奖励的剩余时间，自动刷新。TODO: 待socket主动推送
  watch(bonusesAvailableAt, (availableAt) => {
    Object.keys(timerIds).forEach((key) => {
      clearTimeout(timerIds[key]);
      delete timerIds[key];
    });

    Object.entries(availableAt).forEach(([key, value]) => {
      if (!value)
        return;

      const now = Date.now();
      const delay = value - now;

      if (delay > 0) {
        timerIds[key] = setTimeout(bonusesQry.refetch, delay);
      }
    });
  }, { immediate: true });

  usePeriodicPopup(bonuses);

  return { bonusesQry, bonuses, bonusesAvailableAt, bonuseAvailableCount };
});

/** 等级信息 */
export const useLevelQuery = createSharedComposable(() => {
  const levelInfoQry = useQuery({
    queryKey: [apis.apiLevelInfo.id],
    queryFn: () => apis.apiLevelInfo(undefined),
  });
  const levelInfo = computed(() => levelInfoQry.data.value);

  return { levelInfoQry, levelInfo };
});

/** 握手协议 */
export const useHandshakeQuery = createSharedComposable(() => {
  const handshakeQry = useQuery({
    queryKey: [apis.apiInitHandshake.id],
    queryFn: () => apis.apiInitHandshake(undefined, { params: { mode: 'pc' } }),
  });
  const handshake = computed(() => handshakeQry.data.value);
  const appName = computed(() => handshake.value?.app_name);
  const isAgent = computed(() => handshake.value?.is_agent === undefined ? undefined : !!handshake.value?.is_agent);

  return { handshakeQry, handshake, appName, isAgent };
});
